package primary.code11_Digit;

import lombok.extern.slf4j.Slf4j;

/**
 * 通过位运算实现加减乘除
 */
@Slf4j
public class Code03_ASPD {
    /**
     * 加法
     * 异或 运算的结果为无进位相加
     * 与 运算的结果左移一位为进位信息
     * <p>
     * 当相加数的其中之一为0时，即可返回结果
     */
    public static int add(int a, int b) {
        while (a != 0 && b != 0) {
            int addWithoutCarry = a ^ b;
            int carry = (a & b) << 1;
            a = addWithoutCarry;
            b = carry;
        }
        return a == 0 ? b : a;
    }

    /**
     * 减法
     * 通过add来实现
     */
    public static int minus(int a, int b) {
        return add(a, add(~b, 1));
    }

    /**
     * 乘法
     */
    public static int multi(int a, int b) {
        int product = 0; // 乘积
        int n = 0;
        while (a != 0 && b != 0) {
            if ((b & 1) == 1) {
                product = add(product, a << n);
            }
            n++;
            b >>= 1;
        }
        return product;
    }

    /**
     * 除法
     */
    public static int divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException();
        }
        int result = 0;
        for (int i = 31; i >= 0; i = minus(i, 1)) {
            if ((a >> i) >= b) { // 刚好大于b
                result |= (1 << i);
                a = minus(a, b << i);
            }
        }
        return result;
    }

    public static void main(String[] args) {
        log.info("{} + {} = {}", 12, 18, add(12, 18)); // 30
        log.info("{} - {} = {}", 12, 18, minus(12, 18)); // -6
        log.info("{} * {} = {}", 12, 18, multi(12, 18)); // 216
        log.info("{} / {} = {}", 100, 18, divide(100, 18)); // 5
    }
}
